package com.ai.cmdc.codeutil.java_generator;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.mybatis.generator.exception.ShellException;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import static org.mybatis.generator.internal.util.messages.Messages.getString;

/**
 * @author zhoulk
 * @Description:
 * @date: 2019/8/9
 */
//@SpringBootTest(classes = ExportSvcApplication.class)
//@RunWith(SpringJUnit4ClassRunner.class)
public class ConfigResolve {
    private List<GeneratedJavaFile> javaFiles;
    private GeneratorConfig generatorConfig;
    private static String interfaceBeanTarget = "../../common/ai-cmdc-interface-bean/src/main/java";
    private static String iDtoPack = "com.ai.cmdc.choreography.input.beans.";
    private static String oDtoPack = "com.ai.cmdc.choreography.output.beans.";
    private static String choreographyDir = "../../choreography/";


    public void resolveConfigXml(String path) throws DocumentException {
        //创建SAXReader对象
        SAXReader reader = new SAXReader();
        //xml文件的位置
        URL sources = ConfigResolve.class.getClassLoader().getResource(path);
        //创建document对象,并读取xml文件 （解析xml文件）
        Document document = reader.read(sources);
        List<Element> elements = document.getRootElement().elements();
        String author = elements.get(0).attributeValue("name");
        List<Element> serviceElements = elements.subList(1, elements.size());
        List<GeneratorConfig.Service> services = resolveServiceNode(serviceElements);
        generatorConfig = new GeneratorConfig();
        generatorConfig.setAuthor(author);
        generatorConfig.setServices(services);
    }

    private List<GeneratorConfig.Service> resolveServiceNode(List<Element> elements) {
        List<GeneratorConfig.Service> services = new ArrayList<>();
        for (Element element : elements) {
            GeneratorConfig.Service service = new GeneratorConfig().new Service();
            String targetProject = element.attributeValue("targetProject");
            String serviceRemark = element.attributeValue("serviceRemark");
            String apiPack = element.attributeValue("apiPack");
            String controllerPack = element.attributeValue("controllerPack");
            String servicePack = element.attributeValue("servicePack");
            String implPack = element.attributeValue("implPack");
            String serviceName = element.attributeValue("serviceName");
            String url = element.attributeValue("url");
            service.setTargetProject(targetProject);
            service.setServiceRemark(serviceRemark);
            service.setApiPack(apiPack);
            service.setControllerPack(controllerPack);
            service.setServicePack(servicePack);
            service.setImplPack(implPack);
            service.setServiceName(serviceName);
            service.setUrl(url);
            services.add(service);
            List<Element> functionElements = element.content();
            List<GeneratorConfig.Function> functions = resolveFunction(functionElements);
            service.setFunctions(functions);
        }
        services.forEach(v -> v.setTargetProject(choreographyDir + v.getTargetProject()));
        return services;
    }

    private List<GeneratorConfig.Function> resolveFunction(List<Element> elements) {
        List<GeneratorConfig.Function> functions = new ArrayList<>();
        for (Element element : elements) {
            GeneratorConfig.Function function = new GeneratorConfig().new Function();
            String functionRemark = element.attributeValue("functionRemark");
            String functionName = element.attributeValue("functionName");
            String url = element.attributeValue("url");
            String method = element.attributeValue("method");
            function.setFunctionRemark(functionRemark);
            function.setFunctionName(functionName);
            function.setUrl(url);
            function.setMethod(method);
            List<Element> oDToElements = element.content();
            List<Element> iDToElements = element.content().subList(1, element.content().size());
            List<GeneratorConfig.Entity> oDTos = resolveEntity(oDToElements);
            List<GeneratorConfig.Entity> iDTos = resolveEntity(iDToElements);
            oDTos.forEach(v -> v.setEntityPack(oDtoPack + v.getEntityPack()));
            iDTos.forEach(v -> v.setEntityPack(iDtoPack + v.getEntityPack()));
            function.setIDTos(iDTos);
            function.setODTo(oDTos.get(0));
            functions.add(function);
        }
        return functions;
    }

    private List<GeneratorConfig.Entity> resolveEntity(List<Element> elements) {
        List<GeneratorConfig.Entity> entities = new ArrayList<>();
        for (Element element : elements) {
            GeneratorConfig.Entity entity = new GeneratorConfig().new Entity();
            String entityTarget = element.attributeValue("entityTarget");
            entityTarget = entityTarget == null ? interfaceBeanTarget : entityTarget;
            String entityPack = element.attributeValue("entityPack");
            String entityName = element.attributeValue("entityName");
            boolean basis = "true".equals(element.attributeValue("basis"));
            boolean create = "true".equals(element.attributeValue("create"));
            boolean list = "true".equals(element.attributeValue("list"));
            String annotionPack = element.attributeValue("annotionPack");
            String annotionStr = element.attributeValue("annotionStr");
            String paramName = element.attributeValue("paramName");
            entity.setEntityTarget(entityTarget);
            entity.setEntityPack(entityPack);
            entity.setEntityName(entityName);
            entity.setBasis(basis);
            entity.setCreate(create);
            entity.setList(list);
            entity.setAnnotionPack(annotionPack);
            entity.setAnnotionStr(annotionStr);
            entity.setParamName(paramName);
            entities.add(entity);
        }
        return entities;
    }





    public void execute() throws ShellException {
        initJavaFile();
        createJavaFile();
    }

    /**
     * 初始化java文件列表
     */
    private void initJavaFile() throws ShellException {
        ClassGeneratorPlugin classGeneratorPlugin = new ClassGeneratorPlugin(generatorConfig);
        javaFiles = classGeneratorPlugin.contextGenerateAdditionalJavaFiles();
    }

    private void createJavaFile() {
        for (GeneratedJavaFile gjf : javaFiles) {
            File targetFile;
            String source;
            try {
                File directory = getDirectory(gjf.getTargetProject(), gjf.getTargetPackage());
                targetFile = new File(directory, gjf.getFileName());
                if (targetFile.exists()) {
                    continue;
                }
                source = gjf.getFormattedContent();

                writeFile(targetFile, source);
            } catch (IOException | ShellException e) {
                e.printStackTrace();
            }
        }
    }

    private void writeFile(File file, String content) throws IOException {
        FileOutputStream out = new FileOutputStream(file);
        OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write(content);
        bw.close();
    }

    private File getDirectory(String targetProject, String targetPackage) throws ShellException {
        System.out.println(System.getProperty("user.dir"));
        File project = new File(targetProject);
        if (!project.isDirectory()) {
            throw new ShellException(getString("Warning.9", //$NON-NLS-1$
                    targetProject));
        }

        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(targetPackage, "."); //$NON-NLS-1$
        while (st.hasMoreTokens()) {
            sb.append(st.nextToken());
            sb.append(File.separatorChar);
        }

        File directory = new File(project, sb.toString());
        if (!directory.isDirectory()) {
            boolean rc = directory.mkdirs();
            if (!rc) {
                throw new ShellException(getString("Warning.10", //$NON-NLS-1$
                        directory.getAbsolutePath()));
            }
        }

        return directory;
    }
}
